package com.ruoyi.cat.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.huifu.bspay.sdk.opps.client.BasePayClient;
import com.huifu.bspay.sdk.opps.core.BasePay;

import com.huifu.bspay.sdk.opps.core.config.MerConfig;
import com.huifu.bspay.sdk.opps.core.exception.BasePayException;
import com.huifu.bspay.sdk.opps.core.request.V2TradeAcctpaymentRefundRequest;
import com.huifu.bspay.sdk.opps.core.request.V2TradePaymentJspayRequest;
import com.huifu.bspay.sdk.opps.core.utils.DateTools;
import com.huifu.bspay.sdk.opps.core.utils.SequenceTools;
import com.ruoyi.cat.domain.AdTicketOrder;
import com.ruoyi.cat.domain.AdTicketRoll;
import com.ruoyi.cat.domain.CatUserbasicTable;
import com.ruoyi.cat.domain.VO.ConfirmRefundVO;
import com.ruoyi.cat.domain.VO.OrderPaymentVO;
import com.ruoyi.cat.service.*;
import com.ruoyi.cat.utils.CommonUtil;
import com.ruoyi.cat.utils.OppsMerchantConfigDemo;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.HttpRequestProxy;
import com.ruoyi.common.utils.OrderUtil;
import com.ruoyi.common.wxpay.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

@Slf4j
@Service
public class OrderPaymentServiceImpl implements OrderPaymentService {


    @Autowired
    private IAdTicketRollService iAdTicketRollService;

    @Autowired
    private IAdTicketOrderService iAdTicketOrderService;

    @Autowired
    private ICatUserbasicTableService iCatUserbasicTableService;

    @Value("${paymentCallback}")
    private String paymentCallback;

    @Value("${wx.pay-callback-host}")
    private String payCallbackHost;

    @Value("${wx.pay-callback-path}")
    private String payCallbackPath;

    @Value("${wx.refund}")
    private String refund;

    private static LinWxPayConfigSampleV2 linWxPayConfig = new LinWxPayConfigSampleV2();





    @Override
    public void doInit(MerConfig merConfig) throws Exception {
        BasePay.initWithMerConfig(merConfig);
    }

    @Override
    public AjaxResult orderPayment(OrderPaymentVO orderPaymentVO) {
        try {
            BasePay.initWithMerConfig(OppsMerchantConfigDemo.getMerchantConfig());
        } catch (Exception e) {
            e.printStackTrace();
        }
        V2TradePaymentJspayRequest request = new V2TradePaymentJspayRequest();

        AdTicketRoll adTicketRoll = iAdTicketRollService.selectAdTicketRollById(orderPaymentVO.getTransId());
        if (adTicketRoll == null) {
            return AjaxResult.error("票卷不存在");
        }
        String order = SequenceTools.getReqSeqId32();
        //adTicketRoll.getMarketPrice();
       // adTicketRoll.getDiscountedPrice();
      //  orderPaymentVO.getQuantity();
     //   BigDecimal actualAmount = adTicketRoll.getMarketPrice().multiply(adTicketRoll.getDiscountedPrice());
      /*  BigDecimal actualAmount = adTicketRoll.getMarketPrice()
                .multiply(adTicketRoll.getDiscountedPrice())
                .multiply(BigDecimal.valueOf(orderPaymentVO.getQuantity()));
        AdTicketOrder adTicketOrder = new AdTicketOrder();

        adTicketOrder.setOrderCode(order);
        adTicketOrder.setTicketId(orderPaymentVO.getTransId());
        adTicketOrder.setUserId(orderPaymentVO.getUserId());
        adTicketOrder.setPrice(actualAmount);
        adTicketOrder.setQuantity(orderPaymentVO.getQuantity());
        adTicketOrder.setType(orderPaymentVO.getType());
        adTicketOrder.setUserName(orderPaymentVO.getUserName());
        adTicketOrder.setPhone(orderPaymentVO.getPhone());
        iAdTicketOrderService.insertAdTicketOrder(adTicketOrder);*/

        // 请求日期
        request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
        // 请求流水号
        request.setReqSeqId(order);
        // 商户号
        request.setHuifuId("6666000173438086");
        // 交易类型
        request.setTradeType("T_MINIAPP");
        // 交易金额
        request.setTransAmt("0.10");
       // request.setTransAmt(actualAmount.setScale(2, BigDecimal.ROUND_HALF_UP).toString());
        // 商品描述
        request.setGoodsDesc(adTicketRoll.getTicketRollTitle());


      //  CatUserbasicTable catUserbasicTable = iCatUserbasicTableService.selectCatUserbasicTableById(orderPaymentVO.getUserId());
        //String openId = catUserbasicTable.getOpenId();
        String openId = "";
        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos(openId,paymentCallback);
        request.setExtendInfo(extendInfoMap);

        // 3. 发起API调用
        Map<String, Object> response = null;
        try {
            response = BasePayClient.request(request, false);
        } catch (BasePayException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        System.out.println("返回数据:" + JSONObject.toJSONString(response));
        return AjaxResult.success(response);
    }

    @Override
    public AjaxResult wxOrderPayment(OrderPaymentVO orderPaymentVO) {
        AdTicketRoll adTicketRoll = iAdTicketRollService.selectAdTicketRollById(orderPaymentVO.getTransId());
        if (adTicketRoll == null) {
            return AjaxResult.error("票卷不存在");
        }
       //新增库存校验逻辑
        Long quantity = orderPaymentVO.getQuantity();
        Long inventory = adTicketRoll.getInventory();
        if (quantity > inventory) {
            return AjaxResult.error("库存不足，剩余库存：" + inventory);
        }
        BigDecimal actualAmount = adTicketRoll.getMarketPrice()
                .multiply(adTicketRoll.getDiscountedPrice())
                .multiply(BigDecimal.valueOf(orderPaymentVO.getQuantity()));
        BigDecimal regis = OrderUtil.calculateProduct(orderPaymentVO.getQuantity(), actualAmount);
        String orderNo =  OrderUtil.makeOrderNo();
        AdTicketOrder adTicketOrder = new AdTicketOrder();
        adTicketOrder.setOrderCode(orderNo);
        adTicketOrder.setTicketId(orderPaymentVO.getTransId());
        adTicketOrder.setUserId(orderPaymentVO.getUserId());
        adTicketOrder.setPrice(actualAmount);
        adTicketOrder.setQuantity(orderPaymentVO.getQuantity());
        adTicketOrder.setType(orderPaymentVO.getType());
        adTicketOrder.setUserName(orderPaymentVO.getUserName());
        adTicketOrder.setPhone(orderPaymentVO.getPhone());
        iAdTicketOrderService.insertAdTicketOrder(adTicketOrder);
        adTicketRoll.setQuantity(Math.max(adTicketRoll.getQuantity() - adTicketOrder.getQuantity(), 0));
        iAdTicketRollService.updateAdTicketRollBy(adTicketRoll);
        iAdTicketRollService.updateAdTicketRollBy(adTicketRoll);
        CatUserbasicTable catUserbasicTable = iCatUserbasicTableService.selectCatUserbasicTableById(orderPaymentVO.getUserId());
        Map<String, String>  map = apiMakePreOrderParams(regis,orderNo ,"APP",catUserbasicTable.getOpenId());
        return AjaxResult.success(map);
    }

    private Map<String, String> apiMakePreOrderParams(BigDecimal serverFinalPrice, String orderNo,String tradeType,String openid) {
        String payCallbackUrl = payCallbackHost + payCallbackPath;
        WXPay wxPay = this.assembleWxPayConfig();
        Map<String, String> data = new HashMap<>();
        data.put("device_info", "Sleeve");
        data.put("fee_type", "CNY");
        data.put("nonce_str", WXPayUtil.generateNonceStr());
        data.put("body", "购买卷");
        data.put("out_trade_no", orderNo);
        data.put("total_fee", OrderUtil.yuanToFenPlainString(serverFinalPrice));
        data.put("spbill_create_ip", HttpRequestProxy.getRemoteRealIp());
        data.put("notify_url", payCallbackUrl);
        data.put("trade_type", "APP");
        data.put("openid", openid);
        String sign ="";
        try {
            sign = WXPayUtil.generateSignature(data, OrderPaymentServiceImpl.linWxPayConfig.getKey(), WXPayConstants.SignType.HMACSHA256);
            data.put("sign",sign);
            Map<String, String> wxOrder = wxPay.unifiedOrder(data);
            Map<String, String> stringMap = makePaySignature(wxOrder);
            return stringMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public WXPay assembleWxPayConfig() {
        WXPay wxPay = null;
        try {
            wxPay = new WXPay(OrderPaymentServiceImpl.linWxPayConfig);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return wxPay;
    }

    private Map<String, String> makePaySignature(Map<String, String> wxOrder) {
        Map<String, String> wxPayMap = new HashMap<>();
        String packages = "prepay_id=" + wxOrder.get("prepay_id");
        wxPayMap.put("appId", OrderPaymentServiceImpl.linWxPayConfig.getAppID());
        wxPayMap.put("timeStamp", OrderUtil.timestamp10());
        wxPayMap.put("nonceStr", RandomStringUtils.randomAlphanumeric(32));
        wxPayMap.put("package", packages);
        wxPayMap.put("signType", "HMAC-SHA256");
        wxPayMap.put("out_trade_no",wxOrder.get("out_trade_no"));
        if (null != wxOrder.get("code_url")){
            wxPayMap.put("code_url", wxOrder.get("code_url"));
        }
        String sign ="";
        try {
            sign = WXPayUtil.generateSignature(wxPayMap, OrderPaymentServiceImpl.linWxPayConfig.getKey(), WXPayConstants.SignType.HMACSHA256);
        } catch (Exception e) {
            e.printStackTrace();
        }

        Map<String, String> miniPayParams = new HashMap<>();

        miniPayParams.put("paySign", sign);
        miniPayParams.putAll(wxPayMap);
        miniPayParams.remove("appId");
        return miniPayParams;
    }

    @Override
    public AjaxResult confirmRefundOracle(ConfirmRefundVO confirmRefundVO) {
        try {
            BasePay.initWithMerConfig(OppsMerchantConfigDemo.getMerchantConfig());
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 2.组装请求参数
        V2TradeAcctpaymentRefundRequest request = new V2TradeAcctpaymentRefundRequest();
        // 请求流水号
        request.setReqSeqId(SequenceTools.getReqSeqId32());
        // 请求日期
        request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
        // 商户号
        request.setHuifuId("6666000108854952");
        // 原余额支付请求日期
        request.setOrgReqDate("20211021");
        // 退款金额
        request.setOrdAmt("0.01");

        // 设置非必填字段
        Map<String, Object> extendInfoMap = getExtendInfos1();
        request.setExtendInfo(extendInfoMap);

        // 3. 发起API调用
        Map<String, Object> response = null;
        try {
            response = BasePayClient.request(request,false);
        } catch (BasePayException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        System.out.println("返回数据:" + JSONObject.toJSONString(response));
        return null;
    }

    @Override
    public AjaxResult refund(String outRefundNo, String transactionId, BigDecimal totalFee, BigDecimal refundFee) {
        String order = "TK"+ DateUtils.generateRandomString();
        //生成sign签名
        Map<String,String> parameters = new TreeMap<>();
        parameters.put("appid", OrderPaymentServiceImpl.linWxPayConfig.getAppID());
        parameters.put("mch_id", OrderPaymentServiceImpl.linWxPayConfig.getMchID());
        parameters.put("nonce_str",WXPayUtil.generateNonceStr());
        parameters.put("sign_type",WXPayConstants.MD5);
        parameters.put("notify_url",payCallbackHost+refund);
        // parameters.put("out_trade_no","");

        //这个是你要退款的流水号，你支付的时候微信返还给你的
        parameters.put("out_trade_no", outRefundNo);
        parameters.put("out_refund_no", order);
        parameters.put("total_fee", CommonUtil.yuanToFenPlainString(totalFee));
        parameters.put("refund_fee",CommonUtil.yuanToFenPlainString(refundFee));
        parameters.put("refund_fee_type","CNY");
        parameters.put("refund_desc","医生24小时未回复");
        //参数不知道什么意思的，对着官方给的API文档看看就清楚了
        String sign ="";
        try {
            sign = WXPayUtil.generateSignature(parameters, OrderPaymentServiceImpl.linWxPayConfig.getKey(),WXPayConstants.SignType.MD5);  //工具类的方法,key就是平台上获取的
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        parameters.put("sign", sign);
        WXPay wxPay = this.assembleWxPayConfig();
        try {
            Map<String, String>  retrunMap = wxPay.refund(parameters);
            log.error("退款请求获取到的数据是什么 {}",retrunMap);
            String return_code =  retrunMap.get("return_code");
            String result_code =  retrunMap.get("result_code");
            String out_trade_no = retrunMap.get("out_trade_no");
            String transaction_id = retrunMap.get("transaction_id");
            if ("SUCCESS".equals(return_code) && return_code.equals(result_code)) {
                //调用成功之后执行创建退款订单接口,还需要一个接口退款回调成功之后修改状态
                //record(out_trade_no,order);
                log.error("退款成功返回的值 out_trade_no {}",out_trade_no);
                log.error("退款 transaction_id {}",transaction_id);
                AdTicketOrder adTicketOrder = new AdTicketOrder();
                adTicketOrder.setOrderCode(outRefundNo);
                adTicketOrder.setRefundOrder(order);
                iAdTicketOrderService.updateAdTicketOrderByOrderCode(adTicketOrder);
                return AjaxResult.success("退款成功");
            }else{
                return AjaxResult.error("退款失败 "+return_code+" "+ result_code);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 非必填字段
     * @return
     */
    private static Map<String, Object> getExtendInfos1() {
        // 设置非必填字段
        Map<String, Object> extendInfoMap = new HashMap<>();
        // 备注
        extendInfoMap.put("remark", "1234567890");
        // 原余额支付请求流水号
        extendInfoMap.put("org_req_seq_id", "202110210012100005");
        // 原余额支付支付全局流水号
        extendInfoMap.put("org_hf_seq_id", "");
        // 分账对象
        // extendInfoMap.put("acct_split_bunch", getAcctSplitBunch());
        // 安全信息
        extendInfoMap.put("risk_check_data", getRiskCheckData());
        return extendInfoMap;
    }

    private static String getRiskCheckData() {
        JSONObject dto = new JSONObject();
        // 转账原因
        dto.put("transfer_type", "04");
        // 产品子类
        dto.put("sub_product", "卡券推广类");

        return dto.toJSONString();
    }

    /**
     * 非必填字段
     * @return
     */
    private static Map<String, Object> getExtendInfos(String openId,String paymentCallback) {
        // 设置非必填字段
        Map<String, Object> extendInfoMap = new HashMap<>();
        // 交易有效期
     //   extendInfoMap.put("time_expire", DateUtils.dateTimeNow());
        // 禁用信用卡标记
        extendInfoMap.put("limit_pay_type", "NO_CREDIT");
        // 是否延迟交易
        extendInfoMap.put("delay_acct_flag", "N");
        // 渠道号
        //extendInfoMap.put("channel_no", "");
        // 手续费扣款标志
        // extendInfoMap.put("fee_flag", "");
        // 营销补贴信息
        // extendInfoMap.put("combinedpay_data", getCombinedpayData());
        // 场景类型
        extendInfoMap.put("pay_scene", "02");
        // 传入分帐遇到优惠的处理规则
        extendInfoMap.put("term_div_coupon_type", "0");
        // 聚合正扫微信拓展参数集合
         extendInfoMap.put("wx_data", getWxData(openId));
        // 银联参数集合
        // extendInfoMap.put("unionpay_data", getUnionpayData());
        // 数字人民币参数集合
        // extendInfoMap.put("dc_data", getDcData());
        // 商户贴息标记
        extendInfoMap.put("fq_mer_discount_flag", "N");
        // 异步通知地址
        extendInfoMap.put("notify_url", paymentCallback);
        // 备注
        extendInfoMap.put("remark", "string");
        // 账户号
        // extendInfoMap.put("acct_id", "");
        return extendInfoMap;
    }

    private static String getWxData(String openId) {
        JSONObject dto = new JSONObject();
        // 附加数据
        dto.put("attach", "");
        // 商品详情
     //   dto.put("detail", getWxGoodsRucan());
        // 设备号
        dto.put("device_info", "");
        // 场景信息
      //  dto.put("scene_info", getWxSceneRucan());
        // 子商户公众账号ID
        dto.put("sub_appid", "wx75224805df5d934a");
        dto.put("sub_openid", "ogwfO63xn5cEnAq5KePl2LjINbf8");
        return dto.toJSONString();
    }


}
